
var util=new Util();

function checkForCollisionWithWalls(dynaObject,newX,newY,direction){
        var hit=false;
        
        /////////// this is the check for the case when i go up or left
        var currentZone = null;
        var currentZoneFreeZone = true;
        
        if((newX<=dynaObject.x && newY==dynaObject.y) || (newX==dynaObject.x && newY<=dynaObject.y)){
	        currentZone = util.getZoneAtPoint(newX,newY);
	        if($defined(currentZone)){
		        currentZoneFreeZone = currentZone.isWalkable();
		        if(currentZoneFreeZone == false){
		              if(dynaObject.myZone==currentZone)
		                  currentZoneFreeZone=true;
		        }
	        }
        }
        //////////////////////// UP LEFT END
        
        /////////////////// RIGHT or DOWN
        var nextZone=null;
        var nextZoneFreeZone = true;
        
        ///////////////// the check for the case when moving right
        if(direction=='left'){
            if(newX>dynaObject.x){ // it means the object goes right, so it makes sense to check
              nextZone=util.getZoneAtPoint(newX+game.standardWidth,newY);
              if($defined(nextZone)){
                nextZoneFreeZone = nextZone.isWalkable();
                /*if(!nextZoneFreeZone){
                    if(nextZone.hasType(dynaObject.type))
                        nextZoneFreeZone=true;
                  }*/
              }
            } else {
                nextZoneFreeZone=true;
            }
        }
        ///////////////// the check for the case when moving down
        if(direction=='top'){
          if(newY>dynaObject.y){// it means the object goes down, so it makes sense to check
            nextZone=util.getZoneAtPoint(newX,newY+game.standardHeight);
            if($defined(nextZone)){
                nextZoneFreeZone = nextZone.isWalkable();
                /*if(!nextZoneFreeZone){
                    if(nextZone.hasType(dynaObject.type))
                        nextZoneFreeZone=true;
                }*/
            }
          } else {
              nextZoneFreeZone=true;
          }
        }
        
        ////////////// RIGHT or DOWN END
        if(!(currentZoneFreeZone && nextZoneFreeZone)){
            hit=true;
            if(dynaObject.type==GAMEUNITTYPE.HERO){
                var movedIntozone = currentZone==null ? nextZone : currentZone;
                if(movedIntozone.hasType(GAMEUNITTYPE.MONSTER)){
                    var badguys = movedIntozone.getElements();
                    for(var i=0;i<badguys.length;i++){
                      if(badguys[i].type==GAMEUNITTYPE.MONSTER)
                          badguys[i].killTheHero();
                          break;
                    }
                  hit=false;
                }
            }
        }
        else{
            /// ideally the code below inside this else should be inside hero class
          /// i put this here, because of performance reasons [i already have the zones computed]
          if(dynaObject.type==GAMEUNITTYPE.HERO){
              var movedIntozone = currentZone==null ? nextZone : currentZone;
              if(movedIntozone.hasType(GAMEUNITTYPE.GOODY))
                  dynaObject.assimilateGoody(movedIntozone);
          }
        }
        return hit;
    }


function keyPressedInputForwarder(e){
    if(window.event){
            //e.cancelBubble is supported by IE - this will kill the bubbling process.
            window.event.cancelBubble = true;
            window.event.returnValue = false;
		}
		else{
            //e.stopPropagation works only in Firefox.
            if (e.stopPropagation) {
                e.stopPropagation();
                e.preventDefault();
            }
	    }
    if(!$defined(game.heart))
        return;
    var keyCode=window.event ? event.keyCode : e.keyCode;
    if(keyCode>=37 && keyCode<=40){
        if($defined(game.hero))
              game.hero.processKeyPressedInput(keyCode);
    } else {
        if(keyCode != 27)
            keyCode = window.event ? keyCode : e.charCode;
        if(keyCode==112 || keyCode==80 || keyCode==27){
            game.pause = game.pause ? false : true;
            if(!game.pause){
                worldbeat();
            }
        }
    }
}
function keyUpInputForwarder(e){
    if(!$defined(game.heart))
            return;
    var keyCode=window.event ? event.keyCode : e.keyCode;
    if(keyCode == 32){
    } else{
        if($defined(game.hero)){
            if(parseInt(keyCode)>=37 && parseInt(keyCode)<=40){
                  game.hero.processKeyUpInput(keyCode);
            }
        }
    }
}
function keyDownInputForwarder(e){
    if(!$defined(game.heart))
        return;
    var keyCode=window.event ? (event.charCode || event.keyCode) : (e.charCode || e.keyCode);
    if(keyCode==32){
                if($defined(game.hero)){
                if($defined(game.lastKeyCodeSentToServer))
                    sendInfoToServer('info=I:'+keyCode+'&'+computeVerificationStatus());
                game.hero.launchBomb();
        }
	if(window.event){
          //e.cancelBubble is supported by IE - this will kill the bubbling process.
          window.event.cancelBubble = true;
          window.event.returnValue = false;
	}else{
          //e.stopPropagation works only in Firefox.
          if (e.stopPropagation) {
              e.stopPropagation();
              e.preventDefault();
          }
	  }
    } else{
        if($defined(game.hero)){
            if(parseInt(keyCode)>=37 && parseInt(keyCode)<=40){
                  game.hero.processKeyDownInput(keyCode);
            }
        }
    }
}

function worldbeat(){
    //if(game.stateCounter>100 && game.stateCounter<105)
   //     console.profile("gabi");
   if(game.pause)
       return;
    if(game.stateCounter<5 && !headless) // this if is a hack, when changing levels, it seems worldbeat gets called more than once and the speed of the game increases,like 2 parallel threads of animating
        clearTimeout(game.heart);
    game.stateCounter++;
    var heartBeatTime = (new Date()).getTime();
    if($defined(game.hero))
      game.hero.moveAlongDirection();
  else
      return;
  var others = game.heroes;
  var othersLength = others.length;
    for(var i=0;i<othersLength;i++){
        if(game.stateCounter>0)
         others[i].moveAlongDirection();
    }
    if(!headless)
        checkGlobalPosition();
    if(game.debug==1)
        debug(heartBeatTime);
    var nextCall = game.speed - ((new Date()).getTime()-heartBeatTime);
    if(nextCall<=0)
        nextCall=2;
    //if(nextCall<game.speed-5)
    //    console.log("nextCall = "+nextCall);
    if($defined(game.heart) && $defined(game.hero)){
        game.heart=setTimeout(worldbeat,nextCall);
    }
}


// if the effect called by world.move* methods is still in action
// we shouldnot call this function again
// so an if should be in place in worldBeat function, on a global variable
//
function checkGlobalPosition() {
    if(!$defined(game.hero))
        return;
    if(game.hero.x+game.standardWidth+game.world.x>game.world.worldWindow.width-(game.standardWidth+10) && game.world.x+game.world.width>game.world.worldWindow.width){
          game.world.moveLeft();
          return;
    }
    if(game.hero.x+game.world.x<game.standardWidth+10 && game.hero.x>0){
        game.world.moveRight();
        return;
    }
    if(game.hero.y+game.standardHeight+game.world.y>game.world.worldWindow.height-(game.standardHeight+10)){
          game.world.moveUp();
          return;
    }
    if(game.hero.y+game.world.y<(game.standardHeight+10)){
        game.world.moveDown();
        return;
    }
}
if(!headless){
    document.onkeypress=keyPressedInputForwarder;
    document.onkeyup=keyUpInputForwarder;
    document.onkeydown=keyDownInputForwarder;

    window.addEvent('domready', startGame);
}

function debug(heartBeatTime){
    if($defined(game.hero)){
        heartBeatTime = (new Date()).getTime() - heartBeatTime;
        game.appendLog('game.hero '+game.hero.x+'-'+game.hero.y+' zone '+game.hero.myZone.x+'-'+game.hero.myZone.y);
        if($defined(game.clickedZone)){
            var elements = game.clickedZone.getElements();
            if($defined(elements) && elements.length>=1){
                    var element = elements[0];
                    if(element.type==GAMEUNITTYPE.FAKEWALL){
                            if($defined(element.goody))
                                    game.appendLog('zoneTypes: '+game.clickedZone.types()+' element goody= '+element.goody.subtype);
                    } else {
                        game.appendLog('zoneTypes: '+game.clickedZone.types());
                    }
            } else
                    game.appendLog('freeZone');
        }
        if(heartBeatTime>game.speed-5)
          console.log('heartBeatTime too long = '+heartBeatTime+' ms');
        game.writeLog();
  }
}

/**
 * clear
 */
function clearCurrentLevel() {

    if($defined(game.heart)){
      clearTimeout(game.heart);
      game.stateCounter=0;
      game.heart=null;
      while(game.activeBombs.length>0){
            game.activeBombs[0].terminate();
      }
      while(game.heroes.length>0){
            game.heroes[0].terminate();
      }
      while(game.fakeWalls.length>0){
            game.fakeWalls[0].terminate();
      }
      while(game.walls.length>0){
            game.walls[0].terminate();
      }
      // exit remains
      while(game.goodies.length>0){
          if(game.goodies[0].subtype==GOODYSUBTYPE.EXIT){
              game.goodies[0].HTMLIncarnation.dispose();
              game.goodies[0].HTMLIncarnation.destroy();
              game.goodies[0].vaporate();
          } else
              game.goodies[0].terminate();
      }

      for(var i=0;i<game.zones.length;i++){
            game.zones[i]=null;
      }
      game.zones=[];
      game.world.resetIntoView();
    }
     game.sound.stopBombSound();
}

function generateNextLevel() {
    game.level++;
    generateLevel(game.hero.cuanta,game.hero.bombExplosionLength,game.hero.numberOfBombs,700,800,1+game.level,true);
}

function generateLevel(heroSpeed,bombExplosionLength,numberOfBombs,worldWidth,worldHeight,numberOfBadGuys,startGame){
    if($defined(game.map))
        generateLevelBasedOnMap();
    else
        generateRandomLevel(heroSpeed,bombExplosionLength,numberOfBombs,worldWidth,worldHeight,numberOfBadGuys,startGame);
}
function generateRandomLevel(heroSpeed,bombExplosionLength,numberOfBombs,worldWidth,worldHeight,numberOfBadGuys,startGame){
        clearCurrentLevel();

	game.heroes = [];
	game.fakeWalls = [];
	game.zones = [];
	game.walls = [];
	game.goodies = [];

	if(worldWidth%game.standardWidth!=0 || worldHeight%game.standardHeight!=0){
            alert('worldWidth='+worldWidth+' must be multiple of '+game.standardWidth+' and worldHeight='+worldHeight+' must be multiple of '+game.standardHeight);
            return;
        }
	game.worldWidth=worldWidth;
	game.worldHeight=worldHeight;

        if($defined(game.world)){
            game.world.changeWorldParameters(worldWidth,worldHeight);
        } else {
            var world=new World(worldWidth,worldHeight);
            world.start();
            game.world=world;
        }

	var xZones = parseInt(game.worldWidth/game.standardWidth);
    var yZones = parseInt(game.worldHeight/game.standardHeight);
    game.zones = new Array(xZones);

    for(var i=0;i<xZones;i++){
        game.zones[i]=new Array(yZones);
        for(var j=0;j<yZones;j++){
            var zone = new StandardZone();
            zone.x=game.standardWidth*i;
            zone.y=game.standardHeight*j;
            game.zones[i][j]=zone;
        }
    }

    var xNumberOfWalls=Math.floor(xZones/2);
    var yNumberOfWalls=Math.floor(yZones/2);
    for(i=0;i<xNumberOfWalls;i++){
        for(j=0;j<yNumberOfWalls;j++){
            var wall = new Wall();
            wall.comeIntoExistence(game.world,game.standardWidth+2*i*game.standardWidth,game.standardHeight+2*j*game.standardHeight);
        }
    }

    var fakeWallsNumberOnX = Math.round(Math.random()*(xZones-3));
    for(i=0;i<yZones;i++){
      for(j=0;j<fakeWallsNumberOnX;j++){
              var xPos = Math.round(Math.random()*xZones);
              if(xPos>1)
                  xPos--;
              if((i==0 && xPos==0) || (i==0 && xPos==1) || (i==1 && xPos==0)) // the hero is here
                  continue;
              if(game.zones[xPos][i].freeZone){
                var fakeWall = new FakeWall();
                fakeWall.setGoody(null);
                fakeWall.comeIntoExistence(game.world,xPos*game.standardWidth,i*game.standardHeight);
              }
      }
    }
    //debugger;
    // always set hero at 0,0
    if(!$defined(game.hero)){
      var hero=new Hero();
      hero.setExplosionLength(bombExplosionLength);
      hero.setNumberOfBombs(numberOfBombs);
      hero.cuanta=heroSpeed;
      hero.score = parseInt($('score').get('text'));
      hero.comeIntoExistence(game.world,0,0);
      game.hero=hero;
    } else {
        game.hero.setPosition(0,0);
    }

    var contorBadGuys=0;
    for(j=0;j<yZones;j++){
        if(contorBadGuys>numberOfBadGuys)
           break;
        var doit=Math.round(Math.random()*4);
        if(doit>2){
          for(var k=0;k<xZones;k++){
              if(j<=4 && k<=4) // the hero is here so we give him some space
                  continue;
              var doit2=Math.round(Math.random()*12);
              var gameZone = game.zones[k][j];
            if(gameZone.freeZone && doit2>8){
                var badguy;
                switch(doit2){
                case 11:
                    badguy = new BadGuy();
                    break;
                case 10:
                    badguy = new ZBadGuy();
                    break;
                case 9:
                    badguy = new FBadGuy();
                    break;
                 default:
                     badguy = new IBadGuy();
                }
                badguy.comeIntoExistence(game.world,gameZone.x,gameZone.y);
                contorBadGuys++;
                if(contorBadGuys>=numberOfBadGuys)
                    break;
            }
          }
        }
    }

    if(startGame){
      game.stateCounter=0;
      if(game.heart==null)
        game.heart=setTimeout(worldbeat,game.speed);
    }
    if(server)
        sendStatusToServer();
}

function generateLevelBasedOnMap(){
	game.heroes = [];
	game.fakeWalls = [];
	game.zones = [];
	game.walls = [];
	game.goodies = [];

        var participantsInfo = game.participants.split(':')[1].split('~');
        var participants = [];
        for(var i=0;i<participantsInfo.length;i++){
            if(participantsInfo[i].length<3)
                continue;
            var participant = participantsInfo[i].split('^');
            participants.push({'username': participant[0],'x': participant[1],'y': participant[2]});
            if(headless){
                java.lang.System.out.println("js: participant="+participant[0]);
            }
        }

        var worldDimensions = game.mapSize.split('x');
	game.worldWidth = worldDimensions[1] * game.standardWidth ;
	game.worldHeight = worldDimensions[0] * game.standardHeight;

        if(!headless){
            if($defined(game.world)){
                game.world.changeWorldParameters(game.worldWidth,game.worldHeight);
            } else {
                var world=new World(game.worldWidth,game.worldHeight);
                world.start();
                game.world=world;
            }
        }

	var xZones = parseInt(game.worldWidth/game.standardWidth);
    var yZones = parseInt(game.worldHeight/game.standardHeight);
    game.zones = new Array(xZones);

    for(var i=0;i<xZones;i++){
        game.zones[i]=new Array(yZones);
        for(var j=0;j<yZones;j++){
            var zone = new StandardZone();
            zone.x=game.standardWidth*i;
            zone.y=game.standardHeight*j;
            game.zones[i][j]=zone;
        }
    }

    var mapLines = game.map.split('N');
    for(var k=0;k<mapLines.length;k++){
     var line = mapLines[k];
    for(var i=0;i<line.length;i++){
        var symbol = line.charAt(i);
        if(symbol==' ')
            continue;
        if(symbol=='#'){
            var wall = new Wall();
            wall.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
        }
        if(symbol=='@'){
            var fakeWall = new FakeWall();
            fakeWall.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
        }
        if(symbol=='B'){
            var fakeWall = new FakeWall();
            fakeWall.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
            fakeWall.setGoody(GOODYSUBTYPE.BOMB);
        }
        if(symbol=='S'){
            var fakeWall = new FakeWall();
            fakeWall.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
            fakeWall.setGoody(GOODYSUBTYPE.SPEED);
        }
        if(symbol=='L'){
            var fakeWall = new FakeWall();
            fakeWall.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
            fakeWall.setGoody(GOODYSUBTYPE.LIFE);
        }
        if(symbol=='1'){
            var badguy = new BadGuy();
            badguy.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
        }
        if(symbol=='2'){
            var badguy = new IBadGuy();
            badguy.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
        }
        if(symbol=='3'){
            var badguy = new ZBadGuy();
            badguy.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
        }
        if(symbol=='4'){
            var badguy = new FBadGuy();
            badguy.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
        }
        if(symbol=='P'){
            if(headless)
                java.lang.System.out.println("participants.length = "+participants.length+" ::: \n"+game.map);
            var participant = null;
            for(var pi=0;pi<participants.length;pi++){
              if(i*game.standardWidth==participants[pi].x && k*game.standardHeight == participants[pi].y){
                  participant = participants[pi];
                  break;
              }
            }
            if(participant.username == game.thisuser){
                if(!$defined(game.hero)){
                    var hero=new ServerHero(participant.username);
                    //hero.setExplosionLength(bombExplosionLength);
                    //hero.setNumberOfBombs(numberOfBombs);
                    hero.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
                    game.hero=hero;
                } else {
                    game.hero.setPosition(i*game.standardWidth,k*game.standardHeight);
                }
            } else {
                var hero=server ? (new ServerHero(participant.username)): (new Hero(participant.username));
                hero.comeIntoExistence(game.world,i*game.standardWidth,k*game.standardHeight);
                if(!headless)
                    hero.setSpriteImage(game.heroes.length+2);
                game.heroes.push(hero);
            }
        }
    }
}
      if(!headless)
        game.heart=window.setTimeout(worldbeat,game.speed);
      if(server && !headless)
        sendStatusToServer();
}

function restartLevel(heroSpeed,bombExplosionLength,numberOfBombs) {
    if(server)
        window.location.href = '/dynagame/listgames';
    else
        generateLevel(heroSpeed,bombExplosionLength,numberOfBombs,700,800,3+game.level,true);
}

function initGame(){
   generateLevel(2,3,1,700,700,2,true);
}

if(server){
    if(!headless)
        window.onbeforeunload = sendExitToServer;
}